package cn.okcode.slowjson.internal;

import java.lang.reflect.*;
import java.util.Collection;

/**
 * @author pyk13
 */
public class BeanUtils {
    public static void setValue(Object object, Field field, Object value) {
        try {
            field.setAccessible(true);
            switch (field.getType().getSimpleName()) {
                case "char":
                    field.setChar(object, TypeCastUtils.castToChar(value));
                    break;
                case "byte":
                    field.setByte(object, TypeCastUtils.castToByte(value));
                    break;
                case "Byte":
                    field.set(object, TypeCastUtils.castToByte(value));
                    break;
                case "short":
                    field.setShort(object, TypeCastUtils.castToShort(value));
                    break;
                case "Short":
                    field.set(object, TypeCastUtils.castToShort(value));
                    break;
                case "int":
                    field.setInt(object, TypeCastUtils.castToInt(value));
                    break;
                case "Integer":
                    field.set(object, TypeCastUtils.castToInt(value));
                    break;
                case "long":
                    field.setLong(object, TypeCastUtils.castToLong(value));
                    break;
                case "Long":
                    field.set(object, TypeCastUtils.castToLong(value));
                    break;
                case "float":
                    field.setFloat(object, TypeCastUtils.castToFloat(value));
                    break;
                case "Float":
                    field.set(object, TypeCastUtils.castToFloat(value));
                    break;
                case "double":
                    field.setDouble(object, TypeCastUtils.castToDouble(value));
                    break;
                case "Double":
                    field.set(object, TypeCastUtils.castToDouble(value));
                    break;
                case "boolean":
                    field.setBoolean(object, TypeCastUtils.castToBoolean(value));
                    break;
                case "Boolean":
                    field.set(object, TypeCastUtils.castToBoolean(value));
                    break;
                case "BigDecimal":
                case "String":
                case "Timestamp":
                case "Date":
                default:
                    field.set(object, value);
                    break;
            }
        } catch (IllegalAccessException e) {
            throw new TypeHandleException("赋值出错，propertyName：" + field.getName());
        }
    }

    public static boolean isGetterStyle(String fieldName) {
        Character prop = null;
        if (fieldName.startsWith("get")) {
            prop = fieldName.charAt(3);
        } else if (fieldName.startsWith("is")) {
            prop = fieldName.charAt(2);
        }
        return prop != null && prop >= 'A' && prop <= 'Z';
    }

    public static boolean isSetterStyle(String fieldName) {
        Character prop = null;
        if (fieldName.startsWith("set")) {
            prop = fieldName.charAt(3);
        }
        return prop != null && prop >= 'A' && prop <= 'Z';
    }

    public static Method findGetter(Class<?> clazz, String fieldName) {
        for (Method method : clazz.getMethods()) {
            if (Modifier.isStatic(method.getModifiers())) {
                continue;
            }
            Class<?> returnType = method.getReturnType();
            if (returnType.equals(Void.TYPE)) {
                continue;
            }
            if (method.getParameterTypes().length != 0) {
                continue;
            }
            String methodName;
            if (isGetterStyle(fieldName)) {
                methodName = fieldName;
            } else {
                String propName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                if (returnType.equals(boolean.class) || returnType.equals(Boolean.class)) {
                    methodName = "is" + propName;
                } else {
                    methodName = "get" + propName;
                }
            }
            if (methodName.equals(method.getName())) {
                return method;
            }
        }
        return null;
    }

    public static Method findSetter(Class<?> clazz, String fieldName) {
        for (Method method : clazz.getMethods()) {
            if (Modifier.isStatic(method.getModifiers())) {
                continue;
            }
            if (method.getReturnType().equals(Void.TYPE)) {
                continue;
            }
            if (method.getParameterTypes().length != 0) {
                continue;
            }
            String methodName;
            if (isSetterStyle(fieldName)) {
                methodName = fieldName;
            } else {
                String propName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                methodName = "set" + propName;
            }
            if (methodName.equals(method.getName())) {
                return method;
            }
        }
        return null;
    }

    public static Object invoke(Method method, Object object, Object... arguments) {
        try {
            if (!method.isAccessible()) {
                method.setAccessible(true);
            }
            return method.invoke(object, arguments);
        } catch (IllegalAccessException e) {
            throw new TypeHandleException("[访问异常]调用方法出错,方法名:" + method.getName());
        } catch (InvocationTargetException e) {
            throw new TypeHandleException("[执行异常]调用方法出错,方法名:" + method.getName());
        }
    }

    public static Object getValue(Field field, Object object) {
        if (!field.isAccessible()) {
            field.setAccessible(true);
        }
        try {
            return field.get(object);
        } catch (IllegalAccessException e) {
            throw new TypeHandleException("获取字段值出错,字段名:" + field.getName());
        }
    }

    public static void copyCollection(Collection<?> src, Object targetArray) {
        int index = 0;
        for (Object item : src) {
            Array.set(targetArray, index, item);
            index++;
        }
    }
}
